// Copyright (C), 2012-2018, Sichuan Xiaoka Technology Co., Ltd.
package utils;

import org.springframework.beans.BeanUtils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * beanUtils list 赋值工具
 *
 * @author 张鹏
 */
public class BeanUtilsList<T> {

    /**
     * 赋值
     *
     * @param source
     * @param des
     */
    public static void copyProperties(Object source, Object des, Class clazz) {
        //判断是否为空
        if (source != null && des != null) {
            //判断是否是list
            if ((source instanceof List) && (des instanceof List)) {
                if(((List) source).size() <= 0){
                    return;
                }
                for (int i = 0; i < ((List) source).size(); i++) {
                    Object o = null;
                    try {
                        o = clazz.newInstance();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                    Object o1 = ((List) source).get(i);
                    if(!(o1 instanceof List)){
                       if(o1  != null && o != null){
                           BeanUtils.copyProperties(o1, o);
                       }
                        ((List) des).add(o);
                    }
                }
                //不是list
            } else {
                BeanUtils.copyProperties(source, des);

            }
        }
    }

    /**
     * 复制到对象
     *
     * @param list
     */
    private static void copyDes(List<Map<String, Object>> list, Object desObj, Class clazz) {
        try {
            //获得属性 子类优先
            //获取子类所有属性
            Field[] beanfields = desObj.getClass().getDeclaredFields();
            //获取父类所有的属性
            Class<?> superclass = desObj.getClass().getSuperclass();
            List<Field> fields = new ArrayList<>();
            fields.addAll(Arrays.asList(beanfields));
            if (superclass != Object.class) {
                Field[] declaredFields = superclass.getDeclaredFields();
                List<Field> fields1 = Arrays.asList(declaredFields);
                fields.addAll(fields1);
            }
            for (int i = 0; i < list.size(); i++) {
                Map<String, Object> map = list.get(i);
                Set<String> strings = map.keySet();
                for (Object o : strings) {
                    Object o1 = map.get(o);
                    if (o1 instanceof List) {
                        for (int j = 0; j < fields.size(); j++) {
                            Field field = fields.get(i);
                            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), desObj.getClass());
                            Method writeMethod = propertyDescriptor.getWriteMethod();
                            String name = propertyDescriptor.getReadMethod().getName();
                            if (name.equals(o)) {
                                writeMethod.invoke(desObj, copyListDes(o1, clazz));
                            }
                        }
                    } else {
                        for (int j = 0; j < fields.size(); j++) {
                            Field field = fields.get(i);
                            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), desObj.getClass());
                            Method writeMethod = propertyDescriptor.getWriteMethod();
                            String name = propertyDescriptor.getReadMethod().getName();
                            if (name.equals(o)) {
                                writeMethod.invoke(desObj, o1);
                                break;
                            }
                        }
                    }
                }
            }

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 赋值到对象list
     *
     * @param o1
     * @param clazz
     */
    private static List copyListDes(Object o1, Class clazz) {
        List<Object> result = new ArrayList<>();
        try {
            if (o1 instanceof List) {
                for (int i = 0; i < ((List) o1).size(); i++) {
                    Object o = ((List) o1).get(i);
                    Object o2 = clazz.newInstance();
                    BeanUtils.copyProperties(o, o2);
                    result.add(o2);

                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return result;

    }

    /**
     * 判断当前元素是否包含list
     */
    private static boolean isArray(Object beanObj) {
        //获取子类所有属性
        Field[] beanfields = beanObj.getClass().getDeclaredFields();
        for (int i = 0; i < beanfields.length; i++) {
            Field beanField = beanfields[i];
            // 此处应该判断beanObj,property不为null
            PropertyDescriptor beanPd = null;
            try {
                beanPd = new PropertyDescriptor(beanField.getName(), beanObj.getClass());
            } catch (IntrospectionException e) {
                e.printStackTrace();
            }
            if (beanPd.getPropertyType() == List.class) {
                return true;
            }

        }
        return false;
    }

    /**
     * 该方法用于传入某实例对象以及对象方法名、修改值，通过放射调用该对象的某个set方法设置修改值
     *
     * @param beanObj
     */
    public static List<Map<String, Object>> setPropertyBean(Object beanObj) {
        List<Map<String, Object>> result = new ArrayList<>();
        copyList(beanObj, result);
        return result;
    }

    /**
     * 提取的方法
     */
    private static void copyList(Object beanObj, List<Map<String, Object>> result) {
        try {
            //获得属性 子类优先
            //获取子类所有属性
            Field[] beanfields = beanObj.getClass().getDeclaredFields();
            //获取父类所有的属性
            Class<?> superclass = beanObj.getClass().getSuperclass();
            List<Field> fields = new ArrayList<>();
            fields.addAll(Arrays.asList(beanfields));
            if (superclass != Object.class) {
                Field[] declaredFields = superclass.getDeclaredFields();
                List<Field> fields1 = Arrays.asList(declaredFields);
                fields.addAll(fields1);
            }
            for (int i = 0; i < fields.size(); i++) {
                Map<String, Object> map = new HashMap<>(16);
                Field beanField = fields.get(i);
                // 此处应该判断beanObj,property不为null
                PropertyDescriptor beanPd = new PropertyDescriptor(beanField.getName(), beanObj.getClass());
                //set方法
                Method setMethodBean = beanPd.getWriteMethod();
                //get方法
                Method readMethodBean = beanPd.getReadMethod();

                if (beanPd.getPropertyType() == List.class) {
                    Object invoke = readMethodBean.invoke(beanObj);
                    if (invoke != null) {
                        map.put(readMethodBean.getName(), setPropertyList(invoke));
                        result.add(map);
                    }
                } else {
                    Object invoke = readMethodBean.invoke(beanObj);
                    if (invoke != null) {
                        map.put(readMethodBean.getName(), invoke);
                        result.add(map);
                    }
                }
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
    }

    /**
     * 该方法用于传入某实例对象以及对象方法名、修改值，通过放射调用该对象的某个set方法设置修改值
     *
     * @param beanObj
     */
    public static List<Map<String, Object>> setPropertyList(Object beanObj) {
        List<Map<String, Object>> result = new ArrayList<>();
        if (beanObj instanceof List) {
            for (int i = 0; i < ((List) beanObj).size(); i++) {
                Object o = ((List) beanObj).get(i);
                copyList(o, result);
            }

        }
        return result;
    }
}
